#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_

#include <atomic>
#include <iostream>
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>

class CThreadPool
{
public:

    CThreadPool(size_t threads = std::thread::hardware_concurrency()):m_stop(false)
    {
        for (size_t i = 0; i < threads; ++i)
        {
            m_vecWorkers.emplace_back([this]() {
                while (1)
                {
                    std::function<void()> task;

                    {
                        std::unique_lock<std::mutex> lock(this->m_queue_mutex);
                        this->m_condition.wait(lock, [this]() {
                            if (this->m_stop || !this->m_queTasks.empty())
                            {
                                return true;
                            }
                            return false;
                        });

                        if (this->m_stop && this->m_queTasks.empty())
                        {
                            return;
                        }

                        task = std::move(this->m_queTasks.front());
                        this->m_queTasks.pop();
                    }

                    task();
                }
            });
        }
    }


    ~CThreadPool()
    {
        Stop();
    
        m_condition.notify_all();
        for (std::thread& worker : m_vecWorkers)
        {
            worker.join();
        }
    }
    
    void Stop()
    {
        std::unique_lock<std::mutex> lock(this->m_queue_mutex);
        m_stop = true;
    }

    template<typename F, typename ...Args>
    auto EnQueue(F&& f, Args && ...args)
    {
        //获取f的返回值类型
        using return_type = std::invoke_result_t<F, Args...>;

        /*
        std::packaged_task 是一个模板类，用于将可调用对象（如函数、lambda 表达式、bind 表达式等）包装成一个任务，该任务可以异步执行，并可以获取其执行结果。
        <return_type()> 指定了 std::packaged_task 的模板参数，即任务的返回类型。这里 return_type 是通过 std::invoke_result_t<F, Args...> 获取的任务函数的返回类型。
        */

        // 创建任务包装器
        auto task = std::make_shared<std::packaged_task<return_type()>> (
            std::bind(std::forward<F>(f), std::forward<Args>(args)...) 
        );

        // 异步获得函数执行的future返回
        std::future<return_type> res = task->get_future();     

        {
            std::unique_lock<std::mutex> lock(this->m_queue_mutex);

            if (m_stop)
            {
                throw std::runtime_error("enqueue on stopped Thread pool");
            }

            m_queTasks.emplace([task = std::move(task)](){
                (*task)();
            });
        }

        m_condition.notify_one();
        return res;
    }

private:
	std::vector<std::thread> m_vecWorkers;
	std::queue<std::function<void()>> m_queTasks;
	std::mutex m_queue_mutex;
	std::condition_variable m_condition;
	std::atomic_bool m_stop;
};


#endif 
